﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Ast.Core.Services.Extensions;
using Ast.Core.WinApi;
using Ast.Framework;
using Castle.Core.Logging;

namespace Ast.Core.Services
{
    public interface IPspCidTableService : IDependency
    {
        void ListObjects(IntPtr handleTablePtr, Func<IntPtr, IntPtr, bool> procObjFunc, int objectOffset);

        IntPtr ProcessType { get; }
        void ListPspCidTableObjects(Func<IntPtr, IntPtr, bool> procObjFunc);
        void ListProcesses(Func<IntPtr, EProcess, string, bool> processFunc);
        void ListThreads(Func<IntPtr, EThread, bool> threadFunc);
    }

    public class PspCidTableService : IPspCidTableService
    {
        private readonly IDeviceController _deviceController;
        private readonly IKernelAddressFinder _kernelAddressFinder;

        private readonly IDictionary<string, string> _driverNames = new Dictionary<string, string>();
        private readonly object _syncRoot = new object();
        private IntPtr _processType;

        public PspCidTableService(IDeviceController deviceController, IKernelAddressFinder kernelAddressFinder)
        {
            _deviceController = deviceController;
            _kernelAddressFinder = kernelAddressFinder;

            Logger = NullLogger.Instance;

            LoadDriverNames();
        }

        public ILogger Logger { get; set; }

        public IntPtr ProcessType
        {
            get
            {
                if (_processType == IntPtr.Zero)
                {
                    lock (_syncRoot)
                    {
                        if (_processType == IntPtr.Zero)
                        {
                            _processType = GetProcessType();
                        }
                    }
                }
                return _processType;
            }
        }

        private IntPtr GetProcessType()
        {
            var currentProcessObject = _deviceController.Invoke("PsGetCurrentProcess");
            var retVal = _deviceController.Invoke("ObGetObjectType", currentProcessObject);
            Logger.InfoFormat("current process object 0x{0:x}, type 0x{1:x}", currentProcessObject.ToInt32(), retVal.ToInt32());
            return retVal;
        }

        private void LoadDriverNames()
        {
            foreach (var logicalDrive in Environment.GetLogicalDrives().Select(x => x.Substring(0, 2)))
            {
                var retVal = new StringBuilder(1024);
                Native.QueryDosDevice(logicalDrive, retVal, 1024);
                _driverNames.Add(logicalDrive, retVal.ToString());
                Logger.InfoFormat("loaded driver name {0}={1}", logicalDrive, retVal.ToString());
            }
        }

        private string ReplaceDriverName(string path)
        {
            // note: can use RtlNtPathNameToDosPathName?
            if (string.IsNullOrEmpty(path)) return path;

            foreach (var driverName in _driverNames)
            {
                if (path.StartsWith(driverName.Value))
                {
                    return string.Format("{0}{1}", driverName.Key, path.Remove(0, driverName.Value.Length));
                }
            }

            return path;
        }

        public void ListObjects(IntPtr handleTablePtr, Func<IntPtr, IntPtr, bool> procObjFunc, int objectOffset)
        {
            if (handleTablePtr == IntPtr.Zero)
            {
                Logger.Error("invalid handle table");
                return;
            }

            var handlerTable = _deviceController.ReadAs<HandlerTable>(handleTablePtr);
            Logger.InfoFormat("TableCode: 0x{0:x}", handlerTable.TableCode.ToInt32());

            var tableCode = handlerTable.TableCode.ToInt32();
            var tableFlag = tableCode & 3;
            var tableAdr = tableCode & 0xFFFFFFFC;
            Logger.InfoFormat("table adr 0x{0:x}, flag {1}", tableAdr, tableFlag);

            SeekTable(new IntPtr((int) tableAdr), tableFlag, procObjFunc, objectOffset);
        }

        private bool SeekTable(IntPtr adr, int lv, Func<IntPtr, IntPtr, bool> procObjFunc, int objectOffset)
        {
            var goOn = true;

            switch (lv)
            {
                case 0:
                    for (var i = 0; i < 511; i++)
                    {
                        adr += 0x8;

                        var obj = _deviceController.ReadAsIntPtr(adr).Value.ToInt32();
                        var objPtr = new IntPtr((int) (obj & 0xFFFFFFF8));
                        if (objPtr == IntPtr.Zero) continue;

                        objPtr += objectOffset; // plus offset
                        var objType = _deviceController.Invoke<IntPtr>("ObGetObjectType", objPtr);
                        Logger.DebugFormat("found object 0x{0:x}, type 0x{1:x}, at 0x{2:x}", obj, objType.ToInt32(), adr.ToInt32());

                        // p1: object pointer
                        // p2: object type
                        // return: continue
                        goOn = procObjFunc(objPtr, objType);
                        if (!goOn) break;
                    }
                    break;
                case 1:
                case 2:
                    var tbAdr = _deviceController.ReadAsIntPtr(adr).Value;
                    while (tbAdr != IntPtr.Zero)
                    {
                        Logger.InfoFormat("seeking table adr 0x{0:x}, level {1}", (uint) tbAdr, lv - 1);
                        goOn = SeekTable(tbAdr, lv - 1, procObjFunc, objectOffset);
                        if (!goOn) break;

                        adr += 0x4;
                        tbAdr = _deviceController.ReadAsIntPtr(adr).Value;
                    }
                    break;
            }

            return goOn;
        }

        public void ListPspCidTableObjects(Func<IntPtr, IntPtr, bool> procObjFunc)
        {
            var pspCidTable = _kernelAddressFinder.FindPspCidTable();
            var handleTableAdr = _deviceController.ReadAsIntPtr(pspCidTable).Value;
            ListObjects(handleTableAdr, procObjFunc, 0); // all entries in pspcidtable are pointing to object directly, no offset
        }

        public void ListProcesses(Func<IntPtr, EProcess, string, bool> processFunc)
        {
            ListPspCidTableObjects((objPtr, objType) =>
            {
                if (objType == ProcessType)
                {
                    var process = _deviceController.ReadAs<EProcess>(objPtr);
                    var processPath = GetProcessImagePath(objPtr);

                    var goOn = processFunc(objPtr, process, processPath);
                    return goOn;
                }
                return true;
            });
        }

        public void ListThreads(Func<IntPtr, EThread, bool> threadFunc)
        {
            ListPspCidTableObjects((objPtr, objType) =>
            {
                if (objType != ProcessType)
                {
                    var thread = _deviceController.ReadAs<EThread>(objPtr);

                    var goOn = threadFunc(objPtr, thread);
                    return goOn;
                }
                return true;
            });
        }

        private string GetProcessImagePath(IntPtr processObject)
        {
            using (var memHandler = _deviceController.AllocateMemory(4))
            {
                var status = _deviceController.Invoke("ObOpenObjectByPointer", processObject /*Object*/, new IntPtr(2) /*HandleAttributes*/, IntPtr.Zero /*PassedAccessState*/, IntPtr.Zero /*DesiredAccess*/, IntPtr.Zero /*ObjectType*/, IntPtr.Zero /*AccessMode*/, memHandler.Value /*Handle*/);
                if (!NtSuccess(status)) return null;

                var handler = _deviceController.ReadAsIntPtr(memHandler.Value).Value;
                using (var memPath = _deviceController.AllocateMemoryForUnicodeString(256))
                {
                    status = _deviceController.Invoke("ZwQueryInformationProcess", handler /*ProcessHandle*/, new IntPtr(27) /*ProcessInformationClass*/, memPath.Value /*ProcessInformation*/, new IntPtr(Marshal.SizeOf<Structure.UnicodeString>() + 256) /*ProcessInformationLength*/, memHandler.Value /*ReturnLength*/);
                    if (!NtSuccess(status)) return null;
                    _deviceController.Invoke("ObCloseHandle", handler, IntPtr.Zero);

                    var path = _deviceController.ReadAsUnicodeString(memPath.Value);
                    Logger.DebugFormat("process path {0}, size {1}", path, _deviceController.ReadAsIntPtr(memHandler.Value).Value.ToInt32());
                    path = ReplaceDriverName(path);
                    return path;
                }
            }
        }

        private bool NtSuccess(IntPtr status)
        {
            return status.ToInt32() >= 0;
        }
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct EThread
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x3c)]
        private byte[] _;

        public IntPtr ServiceTable; // +0x03c ServiceTable     : Ptr32

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x68)]
        private byte[] __;

        public IntPtr Teb; // +0x0a8 Teb              : Ptr32 Void

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x78)]
        private byte[] ___;

        public uint Win32Thread; // +0x124 Win32Thread      : Ptr32

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x228)]
        private byte[] ____;

        public IntPtr StartAddress; // +0x350 StartAddress     : Ptr32 Void

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)]
        private byte[] _____;

        [MarshalAs(UnmanagedType.Struct)]
        public ClientId ClientId; // +0x364 Cid              : _CLIENT_ID

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x28)]
        private byte[] ______;

        public IntPtr Win32StartAddress; // +0x394 Win32StartAddress : Ptr32 Void
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public struct ClientId
    {
        public int UniqueProcess;
        public int UniqueThread;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct EProcess
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0xb4)]
        private byte[] _;

        public int UniqueProcessId; // +0x0b4 UniqueProcessId  : Ptr32 Void

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x98)]
        private byte[] __;

        public IntPtr ObjectTable; // +0x150 ObjectTable      : Ptr32 _HANDLE_TABLE

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x1c)]
        private byte[] ___;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 15)]
        public string ImageFileName; // +0x170 ImageFileName    : [15] UChar
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public struct HandlerTable
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        private byte[] _;

        public IntPtr TableCode; // +0x008 TableCode        : Uint4B

        public IntPtr QuotaProcess;

        public Structure.ListEntry HandleTableList;

        public IntPtr UniqueProcessId;
    }
}

/* from _eprocess to process full path
lkd> dt _eprocess 0x86414cc0
nt!_EPROCESS
   +0x000 Pcb              : _KPROCESS
   +0x0a0 ProcessLock      : _EX_PUSH_LOCK
   +0x0a8 CreateTime       : _LARGE_INTEGER 0x01cefa1e`51e2f786
   +0x0b0 RundownProtect   : _EX_RUNDOWN_REF
   +0x0b4 UniqueProcessId  : 0x00000e10 Void
   +0x0b8 ActiveProcessLinks : _LIST_ENTRY [ 0x85a2ed78 - 0x86411478 ]
   +0x0c0 Flags2           : 0xd000
   +0x0c0 JobNotReallyActive : 0y0
   +0x0c0 AccountingFolded : 0y0
   +0x0c0 NewProcessReported : 0y0
   +0x0c0 ExitProcessReported : 0y0
   +0x0c0 ReportCommitChanges : 0y0
   +0x0c0 LastReportMemory : 0y0
   +0x0c0 ForceWakeCharge  : 0y0
   +0x0c0 CrossSessionCreate : 0y0
   +0x0c0 NeedsHandleRundown : 0y0
   +0x0c0 RefTraceEnabled  : 0y0
   +0x0c0 DisableDynamicCode : 0y0
   +0x0c0 EmptyJobEvaluated : 0y0
   +0x0c0 DefaultPagePriority : 0y101
   +0x0c0 PrimaryTokenFrozen : 0y1
   +0x0c0 ProcessVerifierTarget : 0y0
   +0x0c0 StackRandomizationDisabled : 0y0
   +0x0c0 AffinityPermanent : 0y0
   +0x0c0 AffinityUpdateEnable : 0y0
   +0x0c0 PropagateNode    : 0y0
   +0x0c0 ExplicitAffinity : 0y0
   +0x0c0 ProcessExecutionState : 0y00
   +0x0c0 DisallowStrippedImages : 0y0
   +0x0c0 HighEntropyASLREnabled : 0y0
   +0x0c0 ExtensionPointDisable : 0y0
   +0x0c0 ForceRelocateImages : 0y0
   +0x0c0 ProcessStateChangeRequest : 0y00
   +0x0c0 ProcessStateChangeInProgress : 0y0
   +0x0c0 DisallowWin32kSystemCalls : 0y0
   +0x0c4 Flags            : 0x144d0c01
   +0x0c4 CreateReported   : 0y1
   +0x0c4 NoDebugInherit   : 0y0
   +0x0c4 ProcessExiting   : 0y0
   +0x0c4 ProcessDelete    : 0y0
   +0x0c4 ControlFlowGuardEnabled : 0y0
   +0x0c4 VmDeleted        : 0y0
   +0x0c4 OutswapEnabled   : 0y0
   +0x0c4 Outswapped       : 0y0
   +0x0c4 ForkFailed       : 0y0
   +0x0c4 Wow64VaSpace4Gb  : 0y0
   +0x0c4 AddressSpaceInitialized : 0y11
   +0x0c4 SetTimerResolution : 0y0
   +0x0c4 BreakOnTermination : 0y0
   +0x0c4 DeprioritizeViews : 0y0
   +0x0c4 WriteWatch       : 0y0
   +0x0c4 ProcessInSession : 0y1
   +0x0c4 OverrideAddressSpace : 0y0
   +0x0c4 HasAddressSpace  : 0y1
   +0x0c4 LaunchPrefetched : 0y1
   +0x0c4 Background       : 0y0
   +0x0c4 VmTopDown        : 0y0
   +0x0c4 ImageNotifyDone  : 0y1
   +0x0c4 PdeUpdateNeeded  : 0y0
   +0x0c4 VdmAllowed       : 0y0
   +0x0c4 ProcessRundown   : 0y0
   +0x0c4 ProcessInserted  : 0y1
   +0x0c4 DefaultIoPriority : 0y010
   +0x0c4 ProcessSelfDelete : 0y0
   +0x0c4 SetTimerResolutionLink : 0y0
   +0x0c8 ProcessQuotaUsage : [2] 0x2480
   +0x0d0 ProcessQuotaPeak : [2] 0x542c8
   +0x0d8 PeakVirtualSize  : 0x9d9c000
   +0x0dc VirtualSize      : 0x997d000
   +0x0e0 SessionProcessLinks : _LIST_ENTRY [ 0x8dbe2010 - 0x864114a0 ]
   +0x0e8 ExceptionPortData : 0x88326e38 Void
   +0x0e8 ExceptionPortValue : 0x88326e38
   +0x0e8 ExceptionPortState : 0y000
   +0x0ec Token            : _EX_FAST_REF
   +0x0f0 WorkingSetPage   : 0x4f87b
   +0x0f4 AddressCreationLock : _EX_PUSH_LOCK
   +0x0f8 PageTableCommitmentLock : _EX_PUSH_LOCK
   +0x0fc RotateInProgress : (null) 
   +0x100 ForkInProgress   : (null) 
   +0x104 CommitChargeJob  : (null) 
   +0x108 CloneRoot        : _RTL_AVL_TREE
   +0x10c NumberOfPrivatePages : 0x6be
   +0x110 NumberOfLockedPages : 1
   +0x114 Win32Process     : 0x8f991e20 Void
   +0x118 Job              : (null) 
   +0x11c SectionObject    : 0xba36c7a8 Void
   +0x120 SectionBaseAddress : 0x00950000 Void
   +0x124 Cookie           : 0x84116fa8
   +0x128 VdmObjects       : (null) 
   +0x12c WorkingSetWatch  : (null) 
   +0x130 Win32WindowStation : 0x00000058 Void
   +0x134 InheritedFromUniqueProcessId : 0x00000df4 Void
   +0x138 LdtInformation   : (null) 
   +0x13c OwnerProcessId   : 0
   +0x140 Peb              : 0x7f55d000 _PEB
   +0x144 Session          : 0x8dbe2000 Void
   +0x148 AweInfo          : (null) 
   +0x14c QuotaBlock       : 0x886a8d80 _EPROCESS_QUOTA_BLOCK
   +0x150 ObjectTable      : 0xb2ff2980 _HANDLE_TABLE
   +0x154 DebugPort        : (null) 
   +0x158 PaeTop           : 0x86bad340 Void
   +0x15c DeviceMap        : 0xa3d114c0 Void
   +0x160 EtwDataSource    : 0x85d1fb19 Void
   +0x168 PageDirectoryPte : 0
   +0x170 ImageFileName    : [15]  "windbg.exe"
   +0x17f PriorityClass    : 0x2 ''
   +0x180 SecurityPort     : (null) 
   +0x184 SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO
   +0x188 JobLinks         : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x190 HighestUserAddress : 0x7fff0000 Void
   +0x194 ThreadListHead   : _LIST_ENTRY [ 0x85ce9b1c - 0x860e0c1c ]
   +0x19c ActiveThreads    : 5
   +0x1a0 ImagePathHash    : 0x8345f68a
   +0x1a4 DefaultHardErrorProcessing : 0
   +0x1a8 LastThreadExitStatus : 0n0
   +0x1ac PrefetchTrace    : _EX_FAST_REF
   +0x1b0 LockedPagesList  : (null) 
   +0x1b8 ReadOperationCount : _LARGE_INTEGER 0x2b4
   +0x1c0 WriteOperationCount : _LARGE_INTEGER 0x181
   +0x1c8 OtherOperationCount : _LARGE_INTEGER 0x36f
   +0x1d0 ReadTransferCount : _LARGE_INTEGER 0x40ffca
   +0x1d8 WriteTransferCount : _LARGE_INTEGER 0x532bc3
   +0x1e0 OtherTransferCount : _LARGE_INTEGER 0x3d2b5
   +0x1e8 CommitChargeLimit : 0
   +0x1ec CommitCharge     : 0x83f
   +0x1f0 CommitChargePeak : 0x853
   +0x1f4 Vm               : _MMSUPPORT
   +0x264 MmProcessLinks   : _LIST_ENTRY [ 0x85a2ef24 - 0x86411624 ]
   +0x26c ModifiedPageCount : 0x5f7
   +0x270 ExitStatus       : 0n259
   +0x274 VadRoot          : _RTL_AVL_TREE
   +0x278 VadHint          : 0x860b0a18 Void
   +0x27c VadCount         : 0x78
   +0x280 VadPhysicalPages : 0
   +0x284 VadPhysicalPagesLimit : 0
   +0x288 AlpcContext      : _ALPC_PROCESS_CONTEXT
   +0x298 TimerResolutionLink : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x2a0 TimerResolutionStackRecord : (null) 
   +0x2a4 RequestedTimerResolution : 0
   +0x2a8 SmallestTimerResolution : 0
   +0x2b0 ExitTime         : _LARGE_INTEGER 0x0
   +0x2b8 ActiveThreadsHighWatermark : 7
   +0x2bc LargePrivateVadCount : 0
   +0x2c0 ThreadListLock   : _EX_PUSH_LOCK
   +0x2c4 WnfContext       : 0xa768fba8 Void
   +0x2c8 Spare0           : 0
   +0x2cc SignatureLevel   : 0 ''
   +0x2cd SectionSignatureLevel : 0 ''
   +0x2ce Protection       : _PS_PROTECTION
   +0x2cf SpareByte20      : [1]  ""
   +0x2d0 Flags3           : 0
   +0x2d0 Minimal          : 0y0
   +0x2d4 SvmReserved      : 0n0
   +0x2d8 SvmReserved1     : (null) 
   +0x2dc SvmReserved2     : 0
   +0x2e0 LastFreezeInterruptTime : 0
   +0x2e8 DiskCounters     : 0x86414fb8 _PROCESS_DISK_COUNTERS
   +0x2ec KeepAliveCounter : 0
   +0x2f0 NoWakeKeepAliveCounter : 0

   
lkd> dt _section_object 0xba36c7a8
nt!_SECTION_OBJECT
   +0x000 StartingVa       : 0x00801218 Void
   +0x004 EndingVa         : 0xc3bd948c Void
   +0x008 Parent           : 0xc3bd9514 Void
   +0x00c LeftChild        : (null) 
   +0x010 RightChild       : 0x81d855e0 Void
   +0x014 Segment          : 0xa131c480 _SEGMENT_OBJECT

   
lkd> dt 0xa131c480 _SEGMENT_OBJECT
nt!_SEGMENT_OBJECT
   +0x000 BaseAddress      : 0x8917a9f0 Void
   +0x004 TotalNumberOfPtes : 0x7a
   +0x008 SizeOfSegment    : _LARGE_INTEGER 0x820000
   +0x010 NonExtendedPtes  : 0x7a000
   +0x014 ImageCommitment  : 0
   +0x018 ControlArea      : 0x00950000 _CONTROL_AREA
   +0x01c Subsection       : (null) 
   +0x020 MmSectionFlags   : 0x00000016 _MMSECTION_FLAGS
   +0x024 MmSubSectionFlags : 0xa131c4b0 _MMSUBSECTION_FLAGS

lkd> dt 0xa131c480 _SEGMENT
nt!_SEGMENT
   +0x000 ControlArea      : 0x8917a9f0 _CONTROL_AREA
   +0x004 TotalNumberOfPtes : 0x7a
   +0x008 SegmentFlags     : _SEGMENT_FLAGS
   +0x00c NumberOfCommittedPages : 0
   +0x010 SizeOfSegment    : 0x7a000
   +0x018 ExtendInfo       : 0x00950000 _MMEXTEND_INFO
   +0x018 BasedAddress     : 0x00950000 Void
   +0x01c SegmentLock      : _EX_PUSH_LOCK
   +0x020 u1               : <unnamed-tag>
   +0x024 u2               : <unnamed-tag>
   +0x028 PrototypePte     : 0xa4341828 _MMPTE

 lkd> dt 0x8917a9f0 _CONTROL_AREA -b
nt!_CONTROL_AREA
   +0x000 Segment          : 0xa131c480 
   +0x004 ListHead         : _LIST_ENTRY [ 0x864524c0 - 0x864524c0 ]
      +0x000 Flink            : 0x864524c0 
      +0x004 Blink            : 0x864524c0 
   +0x00c NumberOfSectionReferences : 1
   +0x010 NumberOfPfnReferences : 0x61
   +0x014 NumberOfMappedViews : 1
   +0x018 NumberOfUserReferences : 2
   +0x01c u                : <unnamed-tag>
      +0x000 LongFlags        : 0xa0
      +0x000 Flags            : _MMSECTION_FLAGS
         +0x000 BeingDeleted     : 0y0
         +0x000 BeingCreated     : 0y0
         +0x000 BeingPurged      : 0y0
         +0x000 NoModifiedWriting : 0y0
         +0x000 FailAllIo        : 0y0
         +0x000 Image            : 0y1
         +0x000 Based            : 0y0
         +0x000 File             : 0y1
         +0x000 AttemptingDelete : 0y0
         +0x000 PrefetchCreated  : 0y0
         +0x000 PhysicalMemory   : 0y0
         +0x000 CopyOnWrite      : 0y0
         +0x000 Reserve          : 0y0
         +0x000 Commit           : 0y0
         +0x000 NoChange         : 0y0
         +0x000 WasPurged        : 0y0
         +0x000 UserReference    : 0y0
         +0x000 GlobalMemory     : 0y0
         +0x000 DeleteOnClose    : 0y0
         +0x000 FilePointerNull  : 0y0
         +0x000 PreferredNode    : 0y000000 (0)
         +0x000 GlobalOnlyPerSession : 0y0
         +0x000 UserWritable     : 0y0
         +0x000 Spare            : 0y0000
   +0x020 FilePointer      : _EX_FAST_REF
      +0x000 Object           : 0x864b23bb 
      +0x000 RefCnt           : 0y011
      +0x000 Value            : 0x864b23bb
   +0x024 ControlAreaLock  : 0n0
   +0x028 ModifiedWriteCount : 0
   +0x02c WaitList         : (null) 
   +0x030 u2               : <unnamed-tag>
      +0x000 e2               : <unnamed-tag>
         +0x000 NumberOfSystemCacheViews : 0xffffffff
         +0x000 ImageRelocationStartBit : 0xffffffff
         +0x004 WritableUserReferences : 0n-2147483640
         +0x004 ImageRelocationSizeIn64k : 0y0000000000001000 (0x8)
         +0x004 Unused           : 0y000000000000 (0)
         +0x004 CantMove         : 0y0
         +0x004 BitMap           : 0y00
         +0x004 ImageActive      : 0y1
         +0x008 FlushInProgressCount : 0x8917ab00
         +0x008 NumberOfSubsections : 0x8917ab00
         +0x008 SeImageStub      : 0x8917ab00 
   +0x040 LockedPages      : 1
   +0x048 FileObjectLock   : _EX_PUSH_LOCK
      +0x000 Locked           : 0y0
      +0x000 Waiting          : 0y0
      +0x000 Waking           : 0y0
      +0x000 MultipleShared   : 0y0
      +0x000 Shared           : 0y0000000000000000000000000000 (0)
      +0x000 Value            : 0
      +0x000 Ptr              : (null) 


0x864b23bb & 0xfffffff8 = 0x864b23b8

	  
lkd> dt _file_object 0x864b23b8
nt!_FILE_OBJECT
   +0x000 Type             : 0n5
   +0x002 Size             : 0n128
   +0x004 DeviceObject     : 0x86785b28 _DEVICE_OBJECT
   +0x008 Vpb              : 0x86767ee0 _VPB
   +0x00c FsContext        : 0xa1367d58 Void
   +0x010 FsContext2       : 0xa1367ed0 Void
   +0x014 SectionObjectPointer : 0x8838c820 _SECTION_OBJECT_POINTERS
   +0x018 PrivateCacheMap  : (null) 
   +0x01c FinalStatus      : 0n0
   +0x020 RelatedFileObject : (null) 
   +0x024 LockOperation    : 0 ''
   +0x025 DeletePending    : 0 ''
   +0x026 ReadAccess       : 0x1 ''
   +0x027 WriteAccess      : 0 ''
   +0x028 DeleteAccess     : 0 ''
   +0x029 SharedRead       : 0x1 ''
   +0x02a SharedWrite      : 0 ''
   +0x02b SharedDelete     : 0x1 ''
   +0x02c Flags            : 0x44042
   +0x030 FileName         : _UNICODE_STRING "\Debuggers\windbg.exe"
   +0x038 CurrentByteOffset : _LARGE_INTEGER 0x0
   +0x040 Waiters          : 0
   +0x044 Busy             : 0
   +0x048 LastLock         : (null) 
   +0x04c Lock             : _KEVENT
   +0x05c Event            : _KEVENT
   +0x06c CompletionContext : (null) 
   +0x070 IrpListLock      : 0
   +0x074 IrpList          : _LIST_ENTRY [ 0x864b242c - 0x864b242c ]
   +0x07c FileObjectExtension : (null) 
      
DeviceObject + FileName  = FULL_PATH
 */